﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using TreeBuilder.Contracts;
using System.Windows.Media.Imaging;
using AbstraX.ClientInterfaces;

namespace TreeBuilder.Services
{
    public class NodeInvokeEventArgs<T> : EventArgs
    {
        public T ReturnValue { get; set; }

        public NodeInvokeEventArgs(T returnValue)
        {
            this.ReturnValue = returnValue;
        }
    }

    public delegate void NodeInvokeEventHandler<T>(object sender, NodeInvokeEventArgs<T> e);

    public class NodeImageLoadEventArgs : EventArgs
    {
        public ITreeNodeImage TreeNodeImage { get; set; }

        public NodeImageLoadEventArgs()
        {
        }

        public NodeImageLoadEventArgs(ITreeNodeImage treeNodeImage)
        {
            this.TreeNodeImage = treeNodeImage;
        }
    }

    public delegate void NodeImageLoadHandler(object sender, NodeImageLoadEventArgs e);
    public delegate void ExceptionHandler(object sender, ExceptionEventArgs e);

    public class NodeInvokeOperation<T>
    {
        public event NodeInvokeEventHandler<T> Invoked;
        public event ExceptionHandler ExceptionOccured;
        public ITreeNodeServerEntity Entity { get; set; }
        public Exception Exception { get; set; }

        public NodeInvokeOperation()
        {
        }

        public NodeInvokeOperation(Exception ex)
        {
            this.Exception = ex;
        }

        public bool HasException
        {
            get
            {
                return this.Exception != null;
            }
        }

        public void SetInvoked(ITreeNodeServerEntity entity, T returnValue)
        {
            this.Entity = entity;

            Invoked(entity, new NodeInvokeEventArgs<T>(returnValue));
        }

        public void SetException(ITreeNodeBase parent, Exception ex)
        {
            this.Exception = ex;
            ExceptionOccured(parent, new ExceptionEventArgs(ex));
        }
    }

    public class NodeImageLoadOperation
    {
        public event NodeImageLoadHandler ImageLoaded;
        public event ExceptionHandler ExceptionOccured;
        public ITreeNodeImage TreeNodeImage { get; set; }
        public bool ImageAvailable { get; set; }
        public Exception Exception { get; set; }

        public NodeImageLoadOperation()
        {
        }

        public NodeImageLoadOperation(Exception ex)
        {
            this.Exception = ex;
        }

        public bool HasException
        {
            get
            {
                return this.Exception != null;
            }
        }

        public void SetLoaded(ITreeNodeBase parent, ITreeNodeImage treeNodeImage)
        {
            this.TreeNodeImage = treeNodeImage;
            this.ImageAvailable = true;

            ImageLoaded(parent, new NodeImageLoadEventArgs(treeNodeImage));
        }

        public void SetException(ITreeNodeBase parent, Exception ex)
        {
            ExceptionOccured(parent, new ExceptionEventArgs(ex));
        }
    }

    public class NodeCreateOperation<T> where T : ITreeNodeBase
    {
        public event EventHandler NodeCreated;
        public event ExceptionHandler ExceptionOccured;
        public T NewNode { get; set; }
        public Exception Exception { get; set; }

        public NodeCreateOperation()
        {
        }

        public NodeCreateOperation(Exception ex)
        {
            this.Exception = ex;
        }

        public bool HasException
        {
            get
            {
                return this.Exception != null;
            }
        }

        public void SetException(ITreeNodeBase parent, Exception ex)
        {
            this.Exception = ex;
            ExceptionOccured(parent, new ExceptionEventArgs(ex));
        }

        public void SetCreated(ITreeNodeBase parent, T newNode)
        {
            this.NewNode = newNode;

            NodeCreated(parent, EventArgs.Empty);
        }
    }
}
